#include "KeyboardState.h"

#include <cassert>
#include <SDL_events.h>
#include <SDL_keyboard.h>
#include <cstring>

KeyboardState::KeyboardState()
    : mKeysState(nullptr)
    , mKeyEventState(nullptr)
    , mNumKeys(0)
{

}

void KeyboardState::init() {
    assert(mKeysState == nullptr);
    assert(mKeyEventState == nullptr);

    mKeysState = SDL_GetKeyboardState(&mNumKeys);
    assert(mKeysState != nullptr);
    assert(mNumKeys > 0);

    mKeyEventState = new keyEventState[mNumKeys];
    memset(mKeyEventState, 
        static_cast<uint8_t> (keyEventState::NO_EVENT), 
        mNumKeys * sizeof(keyEventState));
}

void KeyboardState::destroy() {
    assert(mKeysState != nullptr);
    assert(mKeyEventState != nullptr);

    mKeysState = nullptr;
    delete[] mKeyEventState;
    mKeyEventState = nullptr;
}

void KeyboardState::clearKeyEvents() {
    assert(mKeysState != nullptr);
    assert(mKeyEventState != nullptr);

    memset(mKeyEventState, 
        static_cast<uint8_t> (keyEventState::NO_EVENT), 
        mNumKeys * sizeof(keyEventState));
}

void KeyboardState::handleKeyboardEvent(const SDL_KeyboardEvent& event) {
    assert(mKeysState != nullptr);
    assert(mKeyEventState != nullptr);

    // We do not handle key repeat events
    if (event.repeat != 0) {
        return;
    }

    // Update key event state
    const SDL_Scancode keyCode = event.keysym.scancode;
    const keyEventState keyEvent =
        (event.type == SDL_KEYDOWN) ? keyEventState::PRESSED
        : keyEventState::RELEASED;

    mKeyEventState[keyCode] = keyEvent;
}

bool KeyboardState::keyPressedEvent(const SDL_Keycode code) 
{
    assert(mKeysState != nullptr);
    assert(mKeyEventState != nullptr);

    return mKeyEventState[code] == keyEventState::PRESSED;
}

bool KeyboardState::keyReleasedEvent(const SDL_Keycode code) 
{
    assert(mKeysState != nullptr);
    assert(mKeyEventState != nullptr);

    return mKeyEventState[code] == keyEventState::RELEASED;
}

bool KeyboardState::keyPressed(const SDL_Keycode code)
{
    assert(mKeysState != nullptr);
    assert(mKeyEventState != nullptr);

    return (mKeysState[code] == 1);
}